/**
 * performance evaluator
 * container needs to be added to a parent-container
 *
 * example:
 *      let world=new World({
 *          stats:true,
 *      });
 *      let info=world.informationPanel;
 *      if(info)document.body.appendChild(info);
 */
export default class InfoDisplay {
    constructor(world){
        this.init(world);
    }

    //.............................................public........................................................

    get container(){
        return this._container;
    }

    setTime(index){
        this._times[index||0]=performance.now();
    }

    resetMax(){
        this._MaxBroadPhaseTime = 0;
        this._MaxNarrowPhaseTime = 0;
        this._MaxSolvingTime = 0;
        this._MaxTotalTime = 0;
        this._MaxUpdateTime = 0;
    }

    calcBroadPhase(){
        this.setTime( 2 );
        this._broadPhaseTime = this._times[ 2 ] - this._times[ 1 ];
    }

    calcNarrowPhase() {
        this.setTime( 3 );
        this._narrowPhaseTime = this._times[ 3 ] - this._times[ 2 ];
    }

    calcEnd () {
        this.setTime( 5 );
        this._solvingTime = this._times[ 4 ] - this._times[ 3 ];
        this._totalTime = this._times[ 5 ] - this._times[ 0 ];
        this._updateTime = this._times[ 5 ] - this._times[ 4 ];
        if( this._tt === 100 ) this.resetMax();
        if( this._tt > 100 ){
            if( this._broadPhaseTime > this._MaxBroadPhaseTime ) this._MaxBroadPhaseTime = this._broadPhaseTime;
            if( this._narrowPhaseTime > this._MaxNarrowPhaseTime ) this._MaxNarrowPhaseTime = this._narrowPhaseTime;
            if( this._solvingTime > this._MaxSolvingTime ) this._MaxSolvingTime = this._solvingTime;
            if( this._totalTime > this._MaxTotalTime ) this._MaxTotalTime = this._totalTime;
            if( this._updateTime > this._MaxUpdateTime ) this._MaxUpdateTime = this._updateTime;
        }
        this.upFps();
        this._tt ++;
        if(this._tt > 500) this._tt = 0;
    }

    upFps (){
        this._f[1] = performance.now();
        if (this._f[1]-1000>this._f[0]){
            this._f[0] = this._f[1];
            this._fps = this._f[2];
            this._f[2] = 0;
        }
        this._f[2]++;
    }

    get information(){
        return [
            "BroadPhaseType:"+this._broadPhase + "<br><br>",
            "FPS:" + this._fps +" fps<br><br>",
            "rigid-body:"+this._parent._numRigidBodies+"<br>",
            "contact:"+this._parent._contactManager.numContacts+"<br>",
            "pairCheck: "+this._parent._broadPhase.testCount+"<br>",
            "island:"+this._parent._numIslands +"<br><br>",
            "Time in milliseconds<br><br>",
            "broadPhase:"+ (this._broadPhaseTime.toFixed(3)) + " | " + (this._MaxBroadPhaseTime.toFixed(3)) +"<br>",
            "narrowPhase:"+ (this._narrowPhaseTime.toFixed(3))  + " | " + (this._MaxNarrowPhaseTime.toFixed(3)) + "<br>",
            "solving:"+ (this._solvingTime.toFixed(3))+ " | " + (this._MaxSolvingTime.toFixed(3)) + "<br>",
            "total:"+ (this._totalTime.toFixed(3)) + " | " + (this._MaxTotalTime.toFixed(3)) + "<br>",
            "updating:"+ (this._updateTime.toFixed(3)) + " | " + (this._MaxUpdateTime.toFixed(3)) + "<br>"
        ].join("\n");
    }

    toArray(){
        this._infos[0] = this._parent.broadPhase.types;
        this._infos[1] = this._parent.numRigidBodies;
        this._infos[2] = this._parent.numContacts;
        this._infos[3] = this._parent.broadPhase.numPairChecks;
        this._infos[4] = this._parent.numContactPoints;
        this._infos[5] = this._parent.numIslands;
        this._infos[6] = this._broadPhaseTime;
        this._infos[7] = this._narrowPhaseTime;
        this._infos[8] = this._solvingTime;
        this._infos[9] = this._updateTime;
        this._infos[10] = this._totalTime;
        this._infos[11] = this._fps;
        return this._infos;
    }

    update(){
        this._container.innerHTML=this.information;
    }

    //.............................................private.......................................................

    init(world){
        this.initVariable(world);
        this.initContainer();
    }
    initContainer(){
        let ctn=document.createElement('div');
        ctn.style.cssText = 'position:absolute;width:200px;opacity:0.9;left:10px';
        ctn.innerHTML=this.information;
        this._container=ctn;
    }
    initVariable(world){
        this._parent = world;
        this._container=null;
        this._infos = new Float32Array( 13 );
        this._f = [0,0,0];
        this._times = [0,0,0,0];
        this._broadPhase = this._parent._broadPhase._type;
        this._fps = 0;
        this._tt = 0;
        this._broadPhaseTime = 0;
        this._narrowPhaseTime = 0;
        this._solvingTime = 0;
        this._totalTime = 0;
        this._updateTime = 0;
        this._MaxBroadPhaseTime = 0;
        this._MaxNarrowPhaseTime = 0;
        this._MaxSolvingTime = 0;
        this._MaxTotalTime = 0;
        this._MaxUpdateTime = 0;
    }
}